package mt.dummy;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Queue;


import mt.Order;
import mt.comm.ServerComm;
import mt.comm.ServerSideMessage;

/**
 * Communication class for a MicroTrader server. 
 * The MicroTrader server must communicate with clients through this class.
 * 
 * @author Grupo45
 * 
 */
public class ServerCommDummy implements ServerComm {

	public static final int PORT = 8080;
	
	Queue<ServerSideMessage> messageList = new LinkedList<ServerSideMessage>();
	
	
	Queue<DealWithClient> clients = new LinkedList<DealWithClient>();


	/**
	 * Adds a message to a list
	 * 
	 * @param mensagem message to add
	 */
	public void addMessage(ServerSideMessage mensagem){
		messageList.add(mensagem);
	}

	
	/**
	 * Starts the MicroTrader server. The method should setup a server socket and begin to accept connections.
	 * This method must return immediately after a server socket has been setup, and another thread should
	 * started to listen for connections.
	 */
	@Override
	public void start() {
		ServerSocket serverSocket=null;

		while(true) {
			try {
				Socket clientSocket = serverSocket.accept();
				DealWithClient client = new DealWithClient(clientSocket,this);
				clients.add(client);
				client.start();

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}	
	
	/**
	 * Checks if a message from a client is pending. If {@link #hasNextMessage()} returns <b>true</b>, a call to {@link #getNextMessage} 
	 * will return immediately with the oldest message in the queue. If {@link #hasNextMessage()} returns <b>false</b>, a call to 
	 * {@link #getNextMessage} will block until a message has been received.
	 * 
	 * @return <b>true</b> if a message from a client is currently pending, otherwise <b>false</b>. 
	 */
	@Override
	public boolean hasNextMessage() {
		return !(messageList.isEmpty());
	}

	
	/**
	 * Get the next message received from one of the clients. If no message 
	 * is has been received, the method blocks until a message 
	 * is received. If no message will ever be received, <b>null</b> is returned.
	 * 
	 * @return The next message sent by one of the connected clients to the server
	 */
	@Override
	public ServerSideMessage getNextMessage() {
		return messageList.remove();
	}

	
	/**
	 * Report an error to a client
	 * 
	 * @param toNickname nickname of the client
	 * @param error description of the error
	 */
	@Override
	public void sendError(String toNickname, String error) {
		DealWithClient aux = null;
		if(clientIsConnected(toNickname)){
			for(DealWithClient client: clients){
				if(client.getNickname().equals(toNickname))
					aux =  client;
			}

			ClientMessage clientMessage = new ClientMessage(error);
			aux.sendError(clientMessage);

		}
	}

	
	/**
	 * Checks if a client with a certain nickname is currently connected
	 * 
	 * @param nickname nickname of the client to check
	 * @return <b>true</b> if a client with the nickname is currently connected, otherwise <b>false</b>
	 */
	@Override
	public boolean clientIsConnected(String nickname) {
		for(DealWithClient client: clients){
			if(client.getNickname().equals(nickname))
				return true;
		}
		return false;
	}

	
	/**
	 * Disconnect a client
	 * 
	 * @param nickname nickname of the client to disconnect
	 */
	@Override
	public void disconnectClient(String nickname) {
		if(clientIsConnected(nickname)) {
			DealWithClient client=findClient(nickname);
			findClient(nickname).disconnect();
			clients.remove(client);
		}

	}


	/**
	 * Send an order to a client
	 * 
	 * @param receiversNickname nickname of the client to receive the order
	 * @param order order to send
	 */
	@Override
	public void sendOrder(String receiversNickname, Order order) {

		DealWithClient aux = null;

		if(clientIsConnected(receiversNickname)) {
			aux=findClient(receiversNickname);
			ClientMessage clientMessage = new ClientMessage(order);
			aux.sendOrder(clientMessage);
		}

	}

	/**
	 * Find and returns a client
	 * 
	 * @param nickname nickname of the client to find
	 * @return <b>client</b> if exists, otherwise <b>null</b>
	 */
	private DealWithClient findClient(String nickname) {
		for(DealWithClient client: clients){
			if(client.getNickname().equals(nickname))
				return client;
		}
		return null;
	}

}